package com.xxx.springsecuritydemo.config;

import com.xxx.springsecuritydemo.handler.MyAccessDeniedHandler;
import com.xxx.springsecuritydemo.handler.MyAuthenticationFailureHandler;
import com.xxx.springsecuritydemo.handler.MyAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

/**
 * Security配置类
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyAccessDeniedHandler accessDeniedHandler;
    // 自定义登录页面，并且进行其他页面的限制
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 表单提交
        http.formLogin()
                // 自定义表单中username和password的属性名
                .usernameParameter("nickname")
                .passwordParameter("passwd")
                // 自定义登录页面
                .loginPage("/login.html")
                // 必须和表单中的登录处理一致，执行自定义登录逻辑
                .loginProcessingUrl("/login")
                // 登录成功页面跳转
                // 但是现在报405错误，因为当前页面跳转是get请求，而我们使用post上传表单
                .successForwardUrl("/toMain")
                // 设置自定义登录跳转,无法跳转
//                .successForwardUrl("http://www.baidu.com")
                // 登录失败后跳转失败页面，并且重定向登录
                // 使用自定义拦截器重定向需要跳转的主页http://www.baidu.com
                // 自定义登录成功处理器
//                .successHandler(new MyAuthenticationSuccessHandler("/main.html"))
                // 自定义登录失败处理器
//                .failureHandler(new MyAuthenticationFailureHandler("/error.html"));
                // 但是登录失败后页面无法跳转，因为对没有登录的页面进行了拦截
                .failureForwardUrl("/toError");
        //  进行授权
        http.authorizeRequests()
                // 对登录页面放行，不需要进行认证
                // 因为所有的访问控制都是调用的access方法所以我们通过内置参数来设置访问控制权限
                .antMatchers("/login.html").access("permitAll")
//                .antMatchers("/login.html").permitAll()
                // 对error页面放行，登录失败无法认证，但是error和login都可以不用登录就访问
                .antMatchers("/error.html").permitAll()
                // 对main1页面的访问需要有对应权限，严格区分大小写，单一权限
//                .antMatchers("/main1.html").hasAuthority("admin")
                // 拥有任一权限即可访问
//                .antMatchers("/main1.html").hasAnyAuthority("admin","ADMIN")
                // 角色方法也和权限方法一样，需要进行验证和any，不过前缀会加上ROLE_,严格区分大小写
//                .antMatchers("/main1.html").hasRole("abc")
//                .antMatchers("/main1.html").hasAnyRole("abc","ABC")
                // 基于ip地址的访问请求允许
//                .antMatchers("/main1.html").hasIpAddress("127.0.0.1")
                // 果然如果当前的角色不一致，但是放在ip前面则会因为ip而能够正常访问，也区分大小写
//                .antMatchers("/main1.html").access("hasRole('abc')")
                // 表示放行css,js,img目录下的所有资源
//                .antMatchers("/css/**","/js/**","/img/**").permitAll()
                // 将所有目录中后缀为png的文件放行，正则表达式
//                .antMatchers("/**/*.png").permitAll()
                // 放行一个jpg后缀的文件
//                .regexMatchers(".+[.]jpg").permitAll()
                // 指定请求方法来访问该正则资源
//                .regexMatchers(HttpMethod.POST,"/regex").permitAll()
//                .regexMatchers("/lyh/regex").permitAll()
                // mvc匹配前缀路径
                .mvcMatchers("/regex").servletPath("/lyh").permitAll()
                // 所有的请求都必须认证才能访问，即必须登录
                // 但是当前没有限制，所以登录请求也会被拦截
                .anyRequest().authenticated();
                //自定义的授权管理
//                .anyRequest().access("@myServiceImpl.hasPermission(request,authentication)");
        // 异常处理
        http.exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler);


//        http.rememberMe()
//                .tokenRepository()

        // 退出配置
        http.logout()
                // 退出成功后跳转的页面
                .logoutSuccessUrl("/login.html");

        // 可以登录，但是没有页面跳转，返回404页面
        // 关闭csrf功能，跨站请求伪造
        http.csrf().disable();
    }

    // 将密码编码进行容器化管理
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

//    @Bean
//    public PersistentTokenRepository persistentTokenRepository(){
//        // 设置jdbc的实现，还有基于内存的实现
//        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
//        // 设置数据源
//        // 自动建表，第一次启动时开启，第二次启动时注释掉
//        jdbcTokenRepository.setCreateTableOnStartup(true);
//        return jdbcTokenRepository;
//    }
}
